package net.wicp.tams.commons.binlog.replication;

import java.io.IOException;

import net.wicp.tams.commons.Result;
import net.wicp.tams.commons.apiext.ByteUtil;
import net.wicp.tams.commons.binlog.bean.PacketBean;

public abstract class AbsPacketWrite implements IPacketWrite {

	private static final long serialVersionUID = 1L;

	protected int buffSize = 1000;
	protected int sequence = 1;

	@Override
	public final byte[] writeBody() throws IOException {
		Result checkRet = check();
		if (!checkRet.isSuc()) {
			throw new IllegalArgumentException(checkRet.getMessage());
		}
		PacketBean packetBean = PacketBean.builder().build();
		ByteUtil.AssitWrite assitori = new ByteUtil.AssitWrite(buffSize);
		packPacket(assitori);
		packetBean.setBody(assitori.get());
		packetBean.setSequence(sequence);

		ByteUtil.AssitWrite assit = new ByteUtil.AssitWrite(
				packetBean.getLength() + 4 * (packetBean.getLength() / MAX_PACKET_LENGTH + 1));
		if (packetBean.getLength() < MAX_PACKET_LENGTH) { // Single packet
			assit.write(packetBean.getLength(), 3);
			assit.write(packetBean.getSequence(), 1);
			assit.write(packetBean.getBody());
		} else {
			// If the length of the packet is greater than the value of
			// MAX_PACKET_LENGTH,
			// which is defined to be power(2, 24) �C 1 in sql/net_serv.cc, the
			// packet gets
			// split into smaller packets with bodies of MAX_PACKET_LENGTH plus
			// the
			// last
			// packet with a body that is shorter than MAX_PACKET_LENGTH.
			int sequence = packetBean.getSequence();
			byte[][] muliBody = ByteUtil.splitBytes(packetBean.getBody(), MAX_PACKET_LENGTH);
			for (int i = 0; i < muliBody.length; i++) {
				assit.write(MAX_PACKET_LENGTH, 3);
				assit.write(sequence++, 1);
				assit.write(muliBody[i]);
			}
			// The last short packet will always be present even if it must have
			// a
			// zero-length body.
			// It serves as an indicator that there are no more packet parts
			// left in
			// the stream for this large packet.
			assit.write(0, 3);
			assit.write(sequence++, 1);
			assit.write(new byte[0]);
		}
		return assit.get();

	}

	public abstract void packPacket(ByteUtil.AssitWrite assit);

	protected abstract Result check();

}
